<script setup lang="ts">
import { ref, onUnmounted, onMounted, computed, watch, nextTick, defineEmits } from 'vue'
import TaskList from './TaskList.vue'
import Timeline from './Timeline.vue'
import GanttToolbar from './GanttToolbar.vue'
import { useI18n, setCustomMessages } from '../composables/useI18n'
import jsPDF from 'jspdf'
import html2canvas from 'html2canvas'
import type { Task } from '../models/classes/Task'
import type { ToolbarConfig } from '../models/configs/ToolbarConfig'
import { useMessage } from '../composables/useMessage'

const props = withDefaults(defineProps<Props>(), {
  tasks: () => [],
  milestones: () => [],
  onTaskDoubleClick: undefined,
  editComponent: undefined,
  useDefaultDrawer: true,
  onTaskDelete: undefined,
  onMilestoneSave: undefined,
  onMilestoneDelete: undefined,
  onTaskUpdate: undefined,
  onTaskAdd: undefined,
  onMilestoneIconChange: undefined,
  toolbarConfig: () => ({}),
  showToolbar: true,
  onAddTask: undefined,
  onAddMilestone: undefined,
  onTodayLocate: undefined,
  onExportCsv: undefined,
  onExportPdf: undefined,
  onLanguageChange: undefined,
  onThemeChange: undefined,
  onFullscreenChange: undefined,
  localeMessages: undefined,
})

const emit = defineEmits(['taskbar-drag-end', 'taskbar-resize-end', 'milestone-drag-end'])

const { showMessage } = useMessage()

interface Props {
  // 任务数据
  tasks?: Task[]
  // 里程碑数据
  milestones?: Task[]
  // TaskBar双击事件处理器API
  onTaskDoubleClick?: (task: Task) => void
  // 自定义编辑组件
  editComponent?: any
  // 是否使用默认的TaskDrawer
  useDefaultDrawer?: boolean
  // 自定义删除处理器API
  onTaskDelete?: (task: Task) => void
  // 里程碑保存处理器API
  onMilestoneSave?: (milestone: Task) => void
  // 里程碑删除处理器API
  onMilestoneDelete?: (milestoneId: number) => void
  // 任务更新处理器API
  onTaskUpdate?: (task: Task) => void
  // 任务添加处理器API
  onTaskAdd?: (task: Task) => void
  // 里程碑图标变更处理器API
  onMilestoneIconChange?: (milestoneId: number, icon: string) => void
  // 工具栏配置
  toolbarConfig?: ToolbarConfig
  // 是否显示工具栏
  showToolbar?: boolean
  // 工具栏事件处理器
  onAddTask?: () => void
  onAddMilestone?: () => void
  onTodayLocate?: () => void
  onExportCsv?: () => boolean | void
  onExportPdf?: () => void
  onLanguageChange?: (lang: 'zh-CN' | 'en-US') => void
  onThemeChange?: (isDark: boolean) => void
  onFullscreenChange?: (isFullscreen: boolean) => void
  /**
   * 自定义多语言（国际化）配置，结构参考内置 messages['zh-CN']，只需传递需要覆盖的 key 即可。
   * 例如：
   * localeMessages={{ taskName: '自定义任务名', addTask: '自定义新增任务' }}
   * 支持嵌套对象（如 csvHeaders、taskTypeMap 等）。
   * 仅在组件初始化时合并，运行时变更会自动响应。
   */
  localeMessages?: Partial<import('../composables/useI18n').Messages['zh-CN']>
}

const leftPanelWidth = ref(320)

// Timeline组件的引用
const timelineRef = ref<InstanceType<typeof Timeline> | null>(null)

// TaskList的固定总长度（所有列的最小宽度之和 + 边框等额外空间）
// 列宽: 300+120+120+140+140+100+100+100 = 1120px
// 边框: 7个列间边框 * 1px = 7px
// 滚动条预留: 20px
// 额外边距: 13px (task-list-header的左边距3px + 其他10px预留)
const TASK_LIST_MAX_WIDTH = 1120 + 7 + 20 + 13 // = 1160px
const TASK_LIST_MIN_WIDTH = 320 // TaskList最小宽度

const taskListBodyWidth = ref(TASK_LIST_MAX_WIDTH) // TaskList默认宽度
const ganttPanelLeftMinWidth = ref(TASK_LIST_MIN_WIDTH) // 左侧面板最小宽度
const ganttPanelLeftCurrentWidth = ref(TASK_LIST_MIN_WIDTH) // 当前左侧面板宽度
const taskListBodyProposedWidth = ref(TASK_LIST_MAX_WIDTH)
const taskListBodyWidthLimit = ref(TASK_LIST_MAX_WIDTH)

// 简化的限制检查函数：直接基于面板实际宽度判断
const checkWidthLimits = (proposedLeftWidth: number): number => {
  if (proposedLeftWidth < ganttPanelLeftMinWidth.value) {
    return ganttPanelLeftMinWidth.value
  } else if (proposedLeftWidth > taskListBodyWidthLimit.value) {
    return taskListBodyWidthLimit.value
  } else {
    return Math.max(ganttPanelLeftMinWidth.value, proposedLeftWidth)
  }
}

const dragging = ref(false)

function onMouseDown(e: MouseEvent) {
  // 检查事件目标是否是task-list-toggle按钮或其子元素
  const target = e.target as HTMLElement
  if (target.closest('.task-list-toggle')) {
    // 如果点击的是toggle按钮，不执行拖拽逻辑
    return
  }

  // 阻止默认行为和事件冒泡，防止选择文本和触发其他事件
  e.preventDefault()
  e.stopPropagation()

  dragging.value = true

  // ⚠️ 关键修复：初始化拖拽起始点和宽度
  const startX = e.clientX
  const startWidth = leftPanelWidth.value

  // 获取task-list-body的宽度
  const taskListBody = document.querySelector('.task-list-body')
  if (!taskListBody) return
  const taskListBodyRect = taskListBody.getBoundingClientRect()
  taskListBodyWidth.value = taskListBodyRect.width

  // 获取当前inner windows宽度, 右侧预留20%的空间
  taskListBodyProposedWidth.value = window.innerWidth * 0.8 - 6 // 减去splitter宽度

  // 获取左侧面板的最小宽度
  taskListBodyWidthLimit.value = Math.min(taskListBodyProposedWidth.value, taskListBodyWidth.value)

  // 广播拖拽开始事件，通知其他组件暂停悬停效果
  window.dispatchEvent(new CustomEvent('splitter-drag-start'))

  // 在拖拽期间禁用页面选择
  document.body.style.userSelect = 'none'
  document.body.style.webkitUserSelect = 'none'
  document.body.style.cursor = 'col-resize'

  function onMouseMove(ev: MouseEvent) {
    if (!dragging.value) return

    // 阻止默认行为，防止滚动等
    ev.preventDefault()
    ev.stopPropagation()

    const delta = ev.clientX - startX
    const proposedWidth = startWidth + delta

    // 直接使用面板宽度限制检查，无需复杂的坐标计算
    const finalWidth = checkWidthLimits(proposedWidth)
    leftPanelWidth.value = finalWidth
  }

  function onMouseUp() {
    dragging.value = false

    // 广播拖拽结束事件，通知其他组件恢复悬停效果
    window.dispatchEvent(new CustomEvent('splitter-drag-end'))

    // 恢复页面选择和光标
    document.body.style.userSelect = ''
    document.body.style.webkitUserSelect = ''
    document.body.style.cursor = ''

    taskListBodyWidth.value = TASK_LIST_MAX_WIDTH // TaskList默认宽度
    ganttPanelLeftMinWidth.value = TASK_LIST_MIN_WIDTH // 左侧面板最小宽度
    taskListBodyProposedWidth.value = TASK_LIST_MAX_WIDTH
    taskListBodyWidthLimit.value = TASK_LIST_MAX_WIDTH
    ganttPanelLeftCurrentWidth.value = TASK_LIST_MIN_WIDTH // 当前左侧面板宽度

    window.removeEventListener('mousemove', onMouseMove)
    window.removeEventListener('mouseup', onMouseUp)
  }
  window.addEventListener('mousemove', onMouseMove)
  window.addEventListener('mouseup', onMouseUp)
}

// TaskList显示/隐藏状态管理
const isTaskListVisible = ref(true)

// 动画状态管理
const isAnimating = ref(false)
const animationClass = ref('')

// 切换TaskList显示状态
const toggleTaskList = () => {
  // 如果正在动画中，忽略点击
  if (isAnimating.value) return

  // 触发撞击动画
  isAnimating.value = true

  if (isTaskListVisible.value) {
    // 收起时：左侧撞击动画
    animationClass.value = 'impact-left'
  } else {
    // 展开时：右侧撞击动画
    animationClass.value = 'impact-right'
  }

  // 在动画进行到一半时切换状态
  setTimeout(() => {
    isTaskListVisible.value = !isTaskListVisible.value
  }, 200)

  // 动画结束后清理状态
  setTimeout(() => {
    isAnimating.value = false
    animationClass.value = ''
  }, 400)
}

// 监听Timeline的TaskList切换事件
const handleToggleTaskList = (event: CustomEvent) => {
  isTaskListVisible.value = event.detail
}

// --- 事件链路：监听 Timeline 传递上来的拖拽/拉伸事件，并通过 props 回调暴露 ---
function handleTaskBarDragEnd(event: CustomEvent) {
  emit('taskbar-drag-end', event.detail)
}
function handleTaskBarResizeEnd(event: CustomEvent) {
  emit('taskbar-resize-end', event.detail)
}
function handleMilestoneDragEnd(event: CustomEvent) {
  emit('milestone-drag-end', event.detail)
}
onMounted(() => {
  window.addEventListener('taskbar-drag-end', handleTaskBarDragEnd as EventListener)
  window.addEventListener('taskbar-resize-end', handleTaskBarResizeEnd as EventListener)
  window.addEventListener('milestone-drag-end', handleMilestoneDragEnd as EventListener)
})
onUnmounted(() => {
  window.removeEventListener('taskbar-drag-end', handleTaskBarDragEnd as EventListener)
  window.removeEventListener('taskbar-resize-end', handleTaskBarResizeEnd as EventListener)
  window.removeEventListener('milestone-drag-end', handleMilestoneDragEnd as EventListener)
})

// 处理TaskList的任务折叠状态变化
const handleTaskCollapseChange = (task: Task) => {
  // 递归查找并更新原始数据中的任务折叠状态
  const updateTaskCollapsedState = (
    tasks: Task[],
    targetId: number,
    collapsed: boolean,
  ): boolean => {
    for (const t of tasks) {
      if (t.id === targetId) {
        t.collapsed = collapsed
        return true
      }
      if (t.children && t.children.length > 0) {
        if (updateTaskCollapsedState(t.children, targetId, collapsed)) {
          return true
        }
      }
    }
    return false
  }

  // 更新原始任务数据的折叠状态
  if (props.tasks) {
    updateTaskCollapsedState(props.tasks, task.id, task.collapsed ?? false)
  }

  // 触发Timeline重新计算
  updateTaskTrigger.value++
}

// 用于强制触发Timeline重新计算的响应式值
const updateTaskTrigger = ref(0)

// 处理TaskDrawer请求任务列表
const handleRequestTaskList = () => {
  // 创建扁平化的任务列表，包含所有任务和里程碑
  const flatTasks: Task[] = []

  // 递归扁平化任务
  const flattenTasks = (taskList: Task[]) => {
    taskList.forEach(task => {
      flatTasks.push(task)
      if (task.children && task.children.length > 0) {
        flattenTasks(task.children)
      }
    })
  }

  // 添加任务数据
  if (props.tasks) {
    flattenTasks(props.tasks)
  }

  // 添加里程碑数据
  if (props.milestones) {
    flatTasks.push(...props.milestones)
  }

  // 发送任务列表给TaskDrawer
  window.dispatchEvent(new CustomEvent('task-list-updated', { detail: flatTasks }))
}

// 当任务数据变化时，通知TaskDrawer更新
const notifyTaskListUpdated = () => {
  handleRequestTaskList()
}

// 监听任务数据变化，自动通知TaskDrawer
watch(
  [() => props.tasks, () => props.milestones],
  () => {
    // 延迟一点时间确保数据更新完成
    nextTick(() => {
      notifyTaskListUpdated()
    })
  },
  { deep: true, immediate: true },
)

onMounted(() => {
  // 监听Timeline的TaskList切换事件
  window.addEventListener('toggle-task-list', handleToggleTaskList as EventListener)
  // 监听GanttToolbar的全屏切换事件
  window.addEventListener('fullscreen-toggle', handleFullscreenToggle as EventListener)
  // 监听Timeline的任务相关事件
  window.addEventListener('task-updated', handleTaskUpdate as EventListener)
  window.addEventListener('task-added', handleTaskAdd as EventListener)
  window.addEventListener('milestone-icon-changed', handleMilestoneIconChangeEvent as EventListener)
  // 监听里程碑删除和数据变化事件
  window.addEventListener('milestone-deleted', handleMilestoneDeleted as EventListener)
  window.addEventListener('milestone-data-changed', handleMilestoneDataChanged as EventListener)
  // 监听TaskDrawer的任务列表请求
  window.addEventListener('request-task-list', handleRequestTaskList as EventListener)
  // 监听窗口大小变化
  window.addEventListener('resize', handleWindowResize)

  nextTick(() => {
    if (timelineRef.value && typeof timelineRef.value.scrollToTodayCenter === 'function') {
      timelineRef.value.scrollToTodayCenter()
    }
  })
})

onUnmounted(() => {
  dragging.value = false
  // 移除事件监听器
  window.removeEventListener('toggle-task-list', handleToggleTaskList as EventListener)
  window.removeEventListener('fullscreen-toggle', handleFullscreenToggle as EventListener)
  window.removeEventListener('task-updated', handleTaskUpdate as EventListener)
  window.removeEventListener('task-added', handleTaskAdd as EventListener)
  window.removeEventListener(
    'milestone-icon-changed',
    handleMilestoneIconChangeEvent as EventListener,
  )
  window.removeEventListener('milestone-deleted', handleMilestoneDeleted as EventListener)
  window.removeEventListener('milestone-data-changed', handleMilestoneDataChanged as EventListener)
  window.removeEventListener('request-task-list', handleRequestTaskList as EventListener)
  window.removeEventListener('resize', handleWindowResize)
})

// 全屏状态管理
const isFullscreen = ref(false)

// 多语言支持
const { t, locale } = useI18n()
const collapseTaskListText = computed(() => t.value.collapseTaskList)
const expandTaskListText = computed(() => t.value.expandTaskList)

// 为TaskList提供层级数据（保持原始层级结构，只扁平化里程碑）
const tasksForTaskList = computed(() => {
  const result: Task[] = []

  // 如果有里程碑，创建里程碑分组行（扁平化显示）
  if (props.milestones && props.milestones.length > 0) {
    const milestoneGroupRow: Task = {
      id: -1,
      name: t.value.milestoneGroup,
      startDate: '',
      endDate: '',
      type: 'milestone-group',
      children: props.milestones,
      isParent: true,
      collapsed: false,
    }
    result.push(milestoneGroupRow)
  }

  // 添加原始任务数据（完全保持层级结构，不扁平化）
  if (props.tasks && props.tasks.length > 0) {
    result.push(...props.tasks)
  }

  return result
})

// 为Timeline提供正确的扁平化数据
const tasksForTimeline = computed(() => {
  // 通过条件判断访问触发器，确保折叠状态变化时重新计算
  if (updateTaskTrigger.value >= 0) {
    // 触发器起作用，继续执行计算逻辑
  }

  // 创建最终结果数组
  const result: Task[] = []

  // 1. 处理里程碑数据 - 只显示里程碑分组行，不重复显示里程碑本身
  if (props.milestones && props.milestones.length > 0) {
    // 只添加里程碑分组行，里程碑本身的显示由TaskBar组件内部处理
    const milestoneGroupRow: Task = {
      id: -1,
      name: t.value.milestoneGroup,
      startDate: '',
      endDate: '',
      type: 'milestone-group',
      children: props.milestones,
      isParent: true,
      collapsed: false,
    }
    result.push(milestoneGroupRow)
  }

  // 2. 处理任务数据 - 根据TaskList的折叠状态进行智能扁平化
  if (props.tasks && props.tasks.length > 0) {
    // 递归获取所有子任务日期范围的工具函数
    const getAllChildDates = (children: Task[]): { starts: string[]; ends: string[] } => {
      const starts: string[] = []
      const ends: string[] = []

      children.forEach(child => {
        if (child.startDate) starts.push(child.startDate)
        if (child.endDate) ends.push(child.endDate)

        if (child.children && child.children.length > 0) {
          const childDates = getAllChildDates(child.children)
          starts.push(...childDates.starts)
          ends.push(...childDates.ends)
        }
      })

      return { starts, ends }
    }

    // 计算父任务的实际时间范围
    const calculateParentDateRange = (parentTask: Task): { startDate: string; endDate: string } => {
      if (!parentTask.children || parentTask.children.length === 0) {
        return {
          startDate: parentTask.startDate || '',
          endDate: parentTask.endDate || '',
        }
      }

      const { starts, ends } = getAllChildDates(parentTask.children)

      if (starts.length === 0 || ends.length === 0) {
        return {
          startDate: parentTask.startDate || '',
          endDate: parentTask.endDate || '',
        }
      }

      // 找到最早的开始日期和最晚的结束日期
      const earliestStart = starts.reduce((earliest, current) => {
        return new Date(current) < new Date(earliest) ? current : earliest
      })

      const latestEnd = ends.reduce((latest, current) => {
        return new Date(current) > new Date(latest) ? current : latest
      })

      return { startDate: earliestStart, endDate: latestEnd }
    }

    // 递归更新任务树中所有父任务的时间范围（从叶子节点开始向上）
    const updateParentDateRanges = (tasks: Task[]): Task[] => {
      return tasks.map(task => {
        let updatedTask = { ...task }

        // 先递归更新子任务
        if (task.children && task.children.length > 0) {
          updatedTask.children = updateParentDateRanges(task.children)
        }

        // 基于任务类型判断是否为父任务
        const isParent =
          task.type === 'story' || (updatedTask.children && updatedTask.children.length > 0)
        updatedTask.isParent = isParent

        // 如果是父任务且有子任务，重新计算时间范围
        if (isParent && updatedTask.children && updatedTask.children.length > 0) {
          const { startDate, endDate } = calculateParentDateRange(updatedTask)
          updatedTask = {
            ...updatedTask,
            startDate,
            endDate,
          }
        }

        return updatedTask
      })
    }

    // 智能扁平化：只扁平化未折叠的任务
    const smartFlattenTasks = (tasks: Task[], level = 0): Task[] => {
      const flattened: Task[] = []

      tasks.forEach(task => {
        // 添加当前任务（设置层级）
        const processedTask: Task = {
          ...task,
          level,
        }
        flattened.push(processedTask)

        // 关键：只有当父任务未折叠时，才添加子任务到Timeline
        if (task.children && task.children.length > 0 && !task.collapsed) {
          const childTasks = smartFlattenTasks(task.children, level + 1)
          flattened.push(...childTasks)
        }
      })

      return flattened
    }

    // 使用TaskList当前的数据状态进行扁平化
    // 重要：确保使用TaskList组件内部的最新状态，包括折叠状态
    const currentTasks = tasksForTaskList.value.filter(task => task.type !== 'milestone-group')

    // 先更新所有父任务的时间范围（从叶子节点开始向上递归）
    const tasksWithUpdatedDates = updateParentDateRanges(currentTasks)

    // 因为tasksForTaskList返回的是props.tasks的副本，我们需要确保Timeline能看到最新的折叠状态
    // 通过触发器强制重新计算来实现状态同步
    const flattenedTasks = smartFlattenTasks(tasksWithUpdatedDates)
    result.push(...flattenedTasks)
  }

  return result
})

// 计算所有任务和里程碑的最小开始时间和最大结束时间
const timelineDateRange = computed(() => {
  // 扁平化所有任务和子任务
  const flattenTasks = (tasks: Task[]): Task[] => {
    let result: Task[] = []
    tasks.forEach(task => {
      result.push(task)
      if (task.children && task.children.length > 0) {
        result = result.concat(flattenTasks(task.children))
      }
    })
    return result
  }

  let allTasks: Task[] = []
  if (props.tasks) allTasks = allTasks.concat(flattenTasks(props.tasks))
  if (props.milestones) allTasks = allTasks.concat(props.milestones)

  // 过滤出有日期的任务
  const startDates = allTasks
    .map(t => t.startDate)
    .filter(Boolean)
    .map(d => new Date(d!))
  const endDates = allTasks
    .map(t => t.endDate)
    .filter(Boolean)
    .map(d => new Date(d!))

  if (startDates.length === 0 || endDates.length === 0) {
    // 没有任务时，默认以今天为中心
    const today = new Date()
    const min = new Date(today.getFullYear(), today.getMonth() - 6, 1)
    const max = new Date(today.getFullYear(), today.getMonth() + 6 + 1, 0)
    return { min, max }
  }

  // 找到最小开始和最大结束
  const minDate = new Date(Math.min(...startDates.map(d => d.getTime())))
  const maxDate = new Date(Math.max(...endDates.map(d => d.getTime())))

  // 前后各延伸6个月
  const min = new Date(minDate.getFullYear(), minDate.getMonth() - 6, 1)
  const max = new Date(maxDate.getFullYear(), maxDate.getMonth() + 6 + 1, 0)
  return { min, max }
})

// CSV导出处理器包装函数
const csvExportHandler = () => {
  // 如果有外部处理器，先调用它
  if (props.onExportCsv && typeof props.onExportCsv === 'function') {
    const result = props.onExportCsv()
    // 如果外部处理器返回 false，则继续执行默认导出
    // 如果返回其他值或者 undefined，则认为外部已经处理了导出
    if (result === false) {
      defaultExportCsv()
    }
    return
  }

  // 使用默认导出实现
  defaultExportCsv()
}

// 默认CSV导出功能
const defaultExportCsv = () => {
  try {
    // 合并任务和里程碑数据进行导出
    const allData: Task[] = []

    // 添加任务数据
    if (props.tasks && props.tasks.length > 0) {
      allData.push(...props.tasks)
    }

    // 添加里程碑数据
    if (props.milestones && props.milestones.length > 0) {
      allData.push(...props.milestones)
    }

    // 生成CSV内容
    const csvContent = generateCsvContent(allData)

    // 添加UTF-8 BOM以确保在Excel等程序中正确显示中文
    const BOM = '\uFEFF'
    const csvWithBOM = BOM + csvContent

    // 创建下载链接，明确指定UTF-8编码
    const blob = new Blob([csvWithBOM], {
      type: 'text/csv;charset=utf-8;',
    })
    const link = document.createElement('a')
    const url = URL.createObjectURL(blob)

    // 根据当前语言生成文件名
    const currentDate = new Date().toISOString().split('T')[0]
    const filename = `gantt-tasks-${currentDate}.csv`

    link.setAttribute('href', url)
    link.setAttribute('download', filename)
    link.style.visibility = 'hidden'

    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)

    // 清理URL对象
    URL.revokeObjectURL(url)
  } catch (error) {
    console.error('CSV导出失败:', error)
    showMessage('CSV导出失败', 'error', { closable: false })
  }
}

// 生成CSV内容
const generateCsvContent = (tasks: Task[]): string => {
  // 使用多语言的CSV头部 - 动态获取当前语言状态
  const csvHeaders = t.value.csvHeaders
  const headers = [
    csvHeaders.id,
    csvHeaders.taskName,
    csvHeaders.predecessor,
    csvHeaders.assignee,
    csvHeaders.startDate,
    csvHeaders.endDate,
    csvHeaders.estimatedHours,
    csvHeaders.actualHours,
    csvHeaders.progress,
    csvHeaders.type,
    csvHeaders.description,
  ]

  // 安全的字符串转义函数
  const escapeCSVField = (value: any): string => {
    if (value === null || value === undefined) {
      return ''
    }

    const stringValue = String(value)

    // 如果字段包含逗号、引号、换行符等特殊字符，需要用引号包围并转义内部引号
    if (
      stringValue.includes(',') ||
      stringValue.includes('"') ||
      stringValue.includes('\n') ||
      stringValue.includes('\r')
    ) {
      return `"${stringValue.replace(/"/g, '""')}"`
    }

    return stringValue
  }

  // 扁平化任务数据（包含子任务）
  const flattenTasks = (taskList: Task[]): any[] => {
    const result: any[] = []

    taskList.forEach(task => {
      // 添加当前任务，使用安全的数据处理
      result.push({
        id: task.id,
        name: task.name || '',
        predecessor: task.predecessor || '',
        assignee: task.assignee || '',
        startDate: task.startDate || '',
        endDate: task.endDate || '',
        estimatedHours: task.estimatedHours || '',
        actualHours: task.actualHours || '',
        progress: task.progress !== undefined ? `${task.progress}%` : '',
        type: task.type || '',
        description: task.description || '',
      })

      // 递归添加子任务
      if (task.children && task.children.length > 0) {
        result.push(...flattenTasks(task.children))
      }
    })

    return result
  }

  const flatTasks = flattenTasks(tasks)

  // 生成CSV行，使用安全的字符串转义
  const csvRows = [
    // 头部行 - 也需要进行转义处理
    headers.map(header => escapeCSVField(header)).join(','),
    // 数据行
    ...flatTasks.map(task => {
      return [
        escapeCSVField(task.id),
        escapeCSVField(task.name),
        escapeCSVField(task.predecessor),
        escapeCSVField(task.assignee),
        escapeCSVField(task.startDate),
        escapeCSVField(task.endDate),
        escapeCSVField(task.estimatedHours),
        escapeCSVField(task.actualHours),
        escapeCSVField(task.progress),
        escapeCSVField(task.type),
        escapeCSVField(task.description),
      ].join(',')
    }),
  ]

  return csvRows.join('\n')
}

// PDF导出处理器
const pdfExportHandler = async () => {
  try {
    // 获取当前语言的文本
    const loadingText = t.value.pdfExportLoading
    const titleText = t.value.pdfExportTitle
    const dateLabel = t.value.pdfExportDate

    // 创建加载提示
    const loadingEl = document.createElement('div')
    loadingEl.innerHTML = `
      <div style="position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                  background: rgba(0,0,0,0.5); display: flex; align-items: center;
                  justify-content: center; z-index: 10000; color: white; font-size: 16px;">
        ${loadingText}
      </div>
    `
    document.body.appendChild(loadingEl)

    // 获取甘特图容器元素
    const ganttElement = document.querySelector('.gantt-body') as HTMLElement
    if (!ganttElement) {
      throw new Error('找不到甘特图元素')
    }

    // 设置临时样式以确保完整截图
    const originalStyle = {
      overflow: ganttElement.style.overflow,
      height: ganttElement.style.height,
    }

    ganttElement.style.overflow = 'visible'
    ganttElement.style.height = 'auto'

    // 使用html2canvas捕获甘特图
    const canvas = await html2canvas(ganttElement, {
      allowTaint: true,
      useCORS: true,
      scale: 2, // 提高清晰度
      width: ganttElement.scrollWidth,
      height: ganttElement.scrollHeight,
      backgroundColor: '#ffffff',
    })

    // 恢复原始样式
    ganttElement.style.overflow = originalStyle.overflow
    ganttElement.style.height = originalStyle.height

    // 创建PDF
    const imgData = canvas.toDataURL('image/png')
    const pdf = new jsPDF({
      orientation: 'landscape', // 横向布局更适合甘特图
      unit: 'mm',
      format: 'a4',
    })

    // 计算图片在PDF中的尺寸
    const pdfWidth = pdf.internal.pageSize.getWidth()
    const pdfHeight = pdf.internal.pageSize.getHeight()
    const imgWidth = canvas.width
    const imgHeight = canvas.height

    // 计算缩放比例，保持宽高比
    const ratio = Math.min(pdfWidth / imgWidth, pdfHeight / imgHeight)
    const scaledWidth = imgWidth * ratio
    const scaledHeight = imgHeight * ratio

    // 居中放置
    const x = (pdfWidth - scaledWidth) / 2
    const y = (pdfHeight - scaledHeight) / 2

    // 添加标题
    pdf.setFontSize(16)
    pdf.text(titleText, pdfWidth / 2, 15, { align: 'center' })

    // 添加日期
    pdf.setFontSize(10)
    const currentDate = new Date().toLocaleDateString(locale.value)
    pdf.text(`${dateLabel}: ${currentDate}`, pdfWidth - 10, 10, { align: 'right' })

    // 添加甘特图图片
    pdf.addImage(imgData, 'PNG', x, y + 10, scaledWidth, scaledHeight - 15)

    // 如果内容超出一页，分页处理
    if (scaledHeight > pdfHeight - 30) {
      // 计算需要的页数
      const pages = Math.ceil(scaledHeight / (pdfHeight - 30))

      for (let i = 1; i < pages; i++) {
        pdf.addPage()
        const offsetY = -i * (pdfHeight - 30)
        pdf.addImage(imgData, 'PNG', x, y + 10 + offsetY, scaledWidth, scaledHeight - 15)
      }
    }

    // 保存PDF
    const filename = `gantt-chart-${new Date().toISOString().split('T')[0]}.pdf`
    pdf.save(filename)

    // 移除加载提示
    if (loadingEl && loadingEl.parentNode) {
      loadingEl.parentNode.removeChild(loadingEl)
    }
  } catch (error) {
    // 移除加载提示
    const loadingEl = document.querySelector('[style*="position: fixed"]')
    if (loadingEl && loadingEl.parentNode) {
      loadingEl.parentNode.removeChild(loadingEl)
    }

    console.error('PDF导出失败:', error)
    alert('PDF导出失败')
  }
}

// 监听GanttToolbar的全屏切换事件
const handleFullscreenToggle = (event: CustomEvent) => {
  isFullscreen.value = event.detail

  // 调用外部传入的全屏处理器
  if (props.onFullscreenChange && typeof props.onFullscreenChange === 'function') {
    props.onFullscreenChange(isFullscreen.value)
  }
}

// 处理里程碑保存事件
const handleMilestoneSave = (milestone: Task) => {
  // 调用外部传入的里程碑保存处理器
  if (props.onMilestoneSave && typeof props.onMilestoneSave === 'function') {
    props.onMilestoneSave(milestone)
  }

  // 如果没有外部处理器，执行默认的更新逻辑
  // 这里可以添加默认的里程碑数据更新逻辑，比如更新本地数据或者触发重新渲染
}

// 处理任务更新事件
const handleTaskUpdate = (event: CustomEvent) => {
  const updatedTask = event.detail

  // 如果更新的是task类型且有parentId，需要同时更新对应的story进度
  if (updatedTask.type === 'task' && updatedTask.parentId) {
    const updatedStory = calculateStoryProgress(updatedTask.parentId, updatedTask)

    // 先调用外部的任务更新处理器更新子任务
    if (props.onTaskUpdate && typeof props.onTaskUpdate === 'function') {
      props.onTaskUpdate(updatedTask)
    }

    // 如果story进度有变化，也更新story
    if (updatedStory && props.onTaskUpdate && typeof props.onTaskUpdate === 'function') {
      props.onTaskUpdate(updatedStory)
    }
  } else if (props.onTaskUpdate && typeof props.onTaskUpdate === 'function') {
    // 普通任务更新
    props.onTaskUpdate(updatedTask)
  }

  // 关键：任务更新后强制刷新Timeline时间轴
  updateTaskTrigger.value++
}

// 计算story的进度（根据其下所有task的进度计算）
const calculateStoryProgress = (storyId: number, updatedTask?: Task): Task | null => {
  // 获取所有任务的扁平列表
  const allTasks = [...(props.tasks || [])]
  const flatTasks: Task[] = []

  const flattenTasks = (tasks: Task[]) => {
    tasks.forEach(task => {
      flatTasks.push(task)
      if (task.children && task.children.length > 0) {
        flattenTasks(task.children)
      }
    })
  }

  flattenTasks(allTasks)

  // 找到对应的story
  const storyTask = flatTasks.find(task => task.id === storyId && task.type === 'story')
  if (!storyTask) return null

  // 获取该story下所有的task
  let childTasks = flatTasks.filter(task => task.parentId === storyId && task.type === 'task')
  if (childTasks.length === 0) return null

  // 如果有正在更新的task，使用最新的数据替换旧数据
  if (updatedTask && updatedTask.type === 'task' && updatedTask.parentId === storyId) {
    childTasks = childTasks.map(task => (task.id === updatedTask.id ? updatedTask : task))
  }

  // 计算平均进度
  const totalProgress = childTasks.reduce((sum, task) => sum + (task.progress || 0), 0)
  const avgProgress = Math.round(totalProgress / childTasks.length)

  // 如果进度有变化，返回更新后的story
  if (storyTask.progress !== avgProgress) {
    return { ...storyTask, progress: avgProgress }
  }

  // 进度没有变化，返回null
  return null
}

// 处理任务添加事件
const handleTaskAdd = (event: CustomEvent) => {
  const newTask = event.detail
  if (props.onTaskAdd && typeof props.onTaskAdd === 'function') {
    props.onTaskAdd(newTask)
  }
  // 关键：任务新增后强制刷新Timeline时间轴
  updateTaskTrigger.value++
}

// 处理里程碑图标变更事件
const handleMilestoneIconChangeEvent = (event: CustomEvent) => {
  const { milestoneId, icon } = event.detail
  if (props.onMilestoneIconChange && typeof props.onMilestoneIconChange === 'function') {
    props.onMilestoneIconChange(milestoneId, icon)
  }
}

// 处理里程碑删除事件
const handleMilestoneDeleted = (event: CustomEvent) => {
  const { milestoneId } = event.detail

  // 调用外部的里程碑删除处理器
  if (props.onMilestoneDelete && typeof props.onMilestoneDelete === 'function') {
    props.onMilestoneDelete(milestoneId)
  }

  // 强制更新任务触发器，确保Timeline重新计算
  updateTaskTrigger.value++
}

// 处理里程碑数据变化事件
const handleMilestoneDataChanged = () => {
  // 里程碑数据发生变化时，强制更新任务触发器
  // 这会触发 tasksForTimeline 的重新计算
  updateTaskTrigger.value++

  // 确保DOM更新
  nextTick(() => {
    // 可以在这里添加额外的更新逻辑
  })
}

// 保证页面加载后自动居中今日
onMounted(() => {
  nextTick(() => {
    if (timelineRef.value && typeof timelineRef.value.scrollToTodayCenter === 'function') {
      timelineRef.value.scrollToTodayCenter()
    }
  })
})

// 今日定位处理器
const todayLocateHandler = () => {
  // 如果有外部处理器，先调用它
  if (props.onTodayLocate && typeof props.onTodayLocate === 'function') {
    props.onTodayLocate()
    return
  }
  // 使用Timeline组件的scrollToTodayCenter方法，确保今日居中
  if (timelineRef.value && typeof timelineRef.value.scrollToTodayCenter === 'function') {
    timelineRef.value.scrollToTodayCenter()
    return
  }
  // 兜底方案
  defaultTodayLocate()
}

// 里程碑添加处理器
const milestoneAddHandler = () => {
  // 如果有外部处理器，先调用它
  if (props.onAddMilestone && typeof props.onAddMilestone === 'function') {
    props.onAddMilestone()
    return
  }

  // 使用默认里程碑添加实现
  defaultAddMilestone()
}

// 默认里程碑添加功能
const defaultAddMilestone = () => {
  // 派发全局事件，让其他组件处理
  window.dispatchEvent(new CustomEvent('add-milestone'))
}

// 默认今日定位功能
const defaultTodayLocate = () => {
  // 优先使用Timeline组件的scrollToToday方法（已优化的定位逻辑）
  if (timelineRef.value && typeof timelineRef.value.scrollToToday === 'function') {
    timelineRef.value.scrollToToday()
    return
  }

  // 如果Timeline组件或方法不可用，使用备用方案
  const today = new Date()
  const currentMonth = today.getMonth()
  const currentDay = today.getDate()

  // 计算今天在时间轴中的位置
  let totalDays = 0
  for (let i = 0; i < currentMonth; i++) {
    totalDays += new Date(today.getFullYear(), i + 1, 0).getDate()
  }
  totalDays += currentDay

  // 计算滚动位置（每个日期30px宽度）
  const timelinePanel = document.querySelector('.gantt-panel-right')
  const timelinePanelW = timelinePanel?.clientWidth
  const offset = timelinePanelW ? timelinePanelW / 2 : 200 // 偏移量让今天居中显示
  const scrollPosition = (totalDays - 1) * 30 - offset

  // 滚动到指定位置
  const timeline = document.querySelector('.timeline') as HTMLElement
  if (timeline) {
    timeline.scrollLeft = Math.max(0, scrollPosition)

    // 添加今日高亮效果到对应的日期列
    const todayColumn = timeline.querySelector('.day-column.today') as HTMLElement
    if (todayColumn) {
      todayColumn.classList.add('today-highlight')
      setTimeout(() => {
        todayColumn.classList.remove('today-highlight')
      }, 2000)
    }
  }
}

// 窗口大小变化处理函数
const handleWindowResize = () => {
  // 直接检查当前宽度是否仍然有效，如果超出限制则调整
  const adjustedWidth = checkWidthLimits(leftPanelWidth.value)
  if (adjustedWidth !== leftPanelWidth.value) {
    leftPanelWidth.value = adjustedWidth
  }
}

// 设置自定义多语言消息

if (props.localeMessages) {
  setCustomMessages(locale.value, props.localeMessages)
}
watch(
  () => props.localeMessages,
  val => {
    if (val) setCustomMessages(locale.value, val)
  },
  { deep: true },
)
</script>

<template>
  <div
    class="gantt-root"
    :class="{ 'gantt-fullscreen': isFullscreen, 'splitter-dragging': dragging }"
  >
    <!-- 工具栏 -->
    <GanttToolbar
      v-if="props.showToolbar"
      :config="props.toolbarConfig"
      :on-add-task="props.onAddTask"
      :on-add-milestone="milestoneAddHandler"
      :on-today-locate="todayLocateHandler"
      :on-export-csv="csvExportHandler"
      :on-export-pdf="pdfExportHandler"
      :on-language-change="props.onLanguageChange"
      :on-theme-change="props.onThemeChange"
      :on-fullscreen-change="props.onFullscreenChange"
    />

    <!-- 甘特图主体 -->
    <div class="gantt-body">
      <div
        v-if="isTaskListVisible"
        class="gantt-panel gantt-panel-left"
        :style="{ width: leftPanelWidth + 'px' }"
      >
        <TaskList
          :tasks="tasksForTaskList"
          :on-task-double-click="props.onTaskDoubleClick"
          :edit-component="props.editComponent"
          :use-default-drawer="props.useDefaultDrawer"
          @task-collapse-change="handleTaskCollapseChange"
        />
      </div>
      <div class="gantt-splitter" @mousedown="onMouseDown">
        <!-- TaskList切换按钮 - 贴合splitter右侧 -->
        <div
          class="task-list-toggle"
          :title="isTaskListVisible ? collapseTaskListText : expandTaskListText"
          :class="{
            collapsed: !isTaskListVisible,
            [animationClass]: isAnimating,
          }"
          @click.stop="toggleTaskList"
        >
          <svg
            width="16"
            height="16"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2.5"
          >
            <!-- 收起图标 (显示任务列表时) -->
            <polyline v-if="isTaskListVisible" points="15,18 9,12 15,6" />
            <!-- 展开图标 (隐藏任务列表时) -->
            <polyline v-else points="9,18 15,12 9,6" />
          </svg>
        </div>
      </div>

      <div class="gantt-panel gantt-panel-right" :class="{ 'full-width': !isTaskListVisible }">
        <!-- 左侧渐隐效果覆盖层 -->
        <div class="timeline-fade-overlay timeline-fade-left"></div>

        <!-- 右侧渐隐效果覆盖层 -->
        <div class="timeline-fade-overlay timeline-fade-right"></div>

        <Timeline
          ref="timelineRef"
          :tasks="tasksForTimeline"
          :milestones="props.milestones"
          :start-date="timelineDateRange.min"
          :end-date="timelineDateRange.max"
          :on-task-double-click="props.onTaskDoubleClick"
          :edit-component="props.editComponent"
          :use-default-drawer="props.useDefaultDrawer"
          :on-task-delete="props.onTaskDelete"
          :on-milestone-save="handleMilestoneSave"
        />
      </div>
    </div>
  </div>
</template>

<!-- 独立的无scoped样式块处理暗色主题渐隐效果 -->
<style>
/* 暗色主题下的渐隐效果 */
html[data-theme='dark'] .timeline-fade-left {
  background: linear-gradient(
    to right,
    var(--gantt-bg-primary, rgb(35, 35, 35)) 0%,
    rgba(35, 35, 35, 0.95) 0%,
    rgba(35, 35, 35, 0.85) 20%,
    rgba(35, 35, 35, 0.7) 35%,
    rgba(35, 35, 35, 0.5) 50%,
    rgba(35, 35, 35, 0.3) 70%,
    rgba(35, 35, 35, 0.15) 85%,
    transparent 100%
  ) !important;
}

html[data-theme='dark'] .timeline-fade-right {
  background: linear-gradient(
    to left,
    var(--gantt-bg-primary, rgb(35, 35, 35)) 0%,
    rgba(35, 35, 35, 0.95) 0%,
    rgba(35, 35, 35, 0.85) 20%,
    rgba(35, 35, 35, 0.7) 35%,
    rgba(35, 35, 35, 0.5) 50%,
    rgba(35, 35, 35, 0.3) 70%,
    rgba(35, 35, 35, 0.15) 85%,
    transparent 100%
  ) !important;
}
</style>

<style scoped>
@import '../styles/theme-variables.css';
.gantt-root {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background: #f5f7fa;
  box-shadow:
    0 6px 32px 0 rgba(0, 0, 0, 0.1),
    0 1.5px 6px 0 rgba(0, 0, 0, 0.08);
  border-radius: 12px;
  overflow: hidden;
}

.gantt-body {
  display: flex;
  flex: 1;
  min-height: 0;
}

.gantt-panel {
  height: 100%;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
  display: flex;
  flex-direction: column;
}

.gantt-panel-left {
  /* width 由js控制 */
  min-width: 320px;
  transition: width 0.1s;
}

.gantt-panel-right {
  flex: 1;
  min-width: 0;
  position: relative; /* 为渐隐覆盖层定位 */
}

.gantt-panel-right.full-width {
  flex: 1;
  width: 100%;
}

.gantt-splitter {
  position: relative; /* 添加相对定位以支持绝对定位的子元素 */
  width: 6px;
  cursor: col-resize;
  background: var(--gantt-border-light, #e4e7ed);
  transition: all 0.2s ease;
  z-index: 999;
  /* 禁用文本选择和拖拽干扰 */
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  touch-action: none; /* 禁用触摸事件 */
}

.gantt-splitter:hover {
  background: var(--gantt-border-dark, #c0c4cc);
}

.placeholder {
  color: #909399;
  text-align: center;
  margin: auto;
  font-size: 18px;
}

/* Timeline区域左右两侧渐隐覆盖层 */
.timeline-fade-overlay {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 120px;
  pointer-events: none;
  z-index: 100;
  transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  opacity: 0.8;
}

/* 左侧渐隐效果 - 增强版 */
.timeline-fade-left {
  left: 0;
  background: linear-gradient(
    to right,
    var(--gantt-bg-primary, #ffffff) 0%,
    rgba(255, 255, 255, 0.9) 15%,
    rgba(255, 255, 255, 0.7) 30%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0.3) 70%,
    rgba(255, 255, 255, 0.1) 85%,
    transparent 100%
  );
}

/* 右侧渐隐效果 - 增强版 */
.timeline-fade-right {
  right: 0;
  background: linear-gradient(
    to left,
    var(--gantt-bg-primary, #ffffff) 0%,
    rgba(255, 255, 255, 0.9) 15%,
    rgba(255, 255, 255, 0.7) 30%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0.3) 70%,
    rgba(255, 255, 255, 0.1) 85%,
    transparent 100%
  );
}

/* 响应式调整 */
@media (max-width: 768px) {
  .timeline-fade-overlay {
    width: 60px;
  }
}

/* 左侧撞击动画 */
@keyframes slideLeftImpact {
  0% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(-8px);
  }
  40% {
    transform: translateX(2px);
  }
  60% {
    transform: translateX(-3px);
  }
  80% {
    transform: translateX(1px);
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes slideRightImpact {
  0% {
    transform: translateX(0);
  }
  20% {
    transform: translateX(8px);
  }
  40% {
    transform: translateX(-2px);
  }
  60% {
    transform: translateX(3px);
  }
  80% {
    transform: translateX(-1px);
  }
  100% {
    transform: translateX(0);
  }
}

/* TaskList切换按钮样式 */
.task-list-toggle {
  position: absolute;
  top: 0px; /* 紧贴splitter顶端 */
  left: 6px; /* 贴合splitter右侧，稍微调整以更好地附着 */
  width: 15px;
  height: 35px; /* 稍微增加高度，让按钮更明显 */
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid #d9d9d9;
  border-radius: 0 6px 6px 0; /* 右侧圆角，左侧直角贴合splitter */
  cursor: pointer;
  z-index: 1000;
  color: #666;
  transition: all 0.2s ease;
  backdrop-filter: blur(4px);
  box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.15);
}

.task-list-toggle.collapsed:hover {
  box-shadow: -1px 2px 8px rgba(64, 158, 255, 0.25);
}

.task-list-toggle:active {
  transform: scale(1);
}

.task-list-toggle svg {
  transition: transform 0.2s ease;
}

.task-list-toggle:hover svg {
  transform: scale(1.1);
}

/* 暗色主题支持 */
:global(html[data-theme='dark']) .gantt-root {
  background: #1e1e1e !important;
  color: #e5e5e5 !important;
}

:global(html[data-theme='dark']) .gantt-panel {
  background: #2c2c2c !important;
}

:global(html[data-theme='dark']) .gantt-panel-left {
  border-right-color: #4c4c4c !important;
}

:global(html[data-theme='dark']) .gantt-splitter {
  background: linear-gradient(
    to right,
    transparent,
    var(--gantt-border-dark, #666666) 20%,
    var(--gantt-border-dark, #666666) 80%,
    transparent
  ) !important;
  box-shadow: inset 0 0 2px rgba(255, 255, 255, 0.1) !important;
}

:global(html[data-theme='dark']) .gantt-splitter:hover {
  background: linear-gradient(
    to right,
    transparent,
    var(--gantt-primary, #409eff) 20%,
    var(--gantt-primary, #409eff) 80%,
    transparent
  ) !important;
  border-left-color: var(--gantt-primary, #409eff) !important;
  border-right-color: var(--gantt-primary, #409eff) !important;
  box-shadow:
    inset 0 0 4px rgba(64, 158, 255, 0.3),
    0 0 8px rgba(64, 158, 255, 0.2) !important;
}

/* 暗色主题支持 - TaskList切换按钮 */
:global(html[data-theme='dark']) .task-list-toggle {
  background: rgba(42, 42, 42, 0.95) !important;
  border-color: #555555 !important;
  color: #cccccc !important;
  box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4) !important;
}

:global(html[data-theme='dark']) .task-list-toggle.collapsed {
  box-shadow: -1px 1px 4px rgba(0, 0, 0, 0.4) !important;
}

:global(html[data-theme='dark']) .task-list-toggle:hover {
  background: rgba(42, 42, 42, 1) !important;
  color: #569cd6 !important;
  box-shadow: 1px 2px 8px rgba(86, 156, 214, 0.3) !important;
}

:global(html[data-theme='dark']) .task-list-toggle.collapsed:hover {
  box-shadow: -1px 2px 8px rgba(86, 156, 214, 0.3) !important;
}

/* 撞击动画 */
.task-list-toggle.impact-left {
  animation: slideLeftImpact 0.4s ease-out;
}

.task-list-toggle.impact-right {
  animation: slideRightImpact 0.4s ease-out;
}

/* 全屏模式样式 */
.gantt-fullscreen {
  position: fixed !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  z-index: 9999 !important;
  background: #f5f7fa !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  margin: 0 !important;
  padding: 0 !important;
  transition: all 0.3s ease-in-out;
  animation: ganttFullscreenEnter 0.3s ease-out;
}

@keyframes ganttFullscreenEnter {
  0% {
    transform: scale(0.9);
    opacity: 0;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

/* 全屏模式下的甘特图主体 */
.gantt-fullscreen .gantt-body {
  height: calc(100vh - 60px); /* 减去工具栏高度 */
}

/* 全屏模式下的工具栏 */
.gantt-fullscreen .gantt-toolbar {
  border-radius: 0 !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
}

/* 暗色主题下的全屏模式 */
:global(html[data-theme='dark']) .gantt-fullscreen {
  background: #1e1e1e !important;
}

:global(html[data-theme='dark']) .gantt-fullscreen .gantt-toolbar {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important;
}

/* 拖拽分割器时的保护样式 */
.gantt-root.splitter-dragging {
  /* 禁用整个甘特图的文本选择 */
  user-select: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
}

.gantt-root.splitter-dragging .gantt-panel-right {
  /* 拖拽期间禁用Timeline区域的指针事件 */
  pointer-events: none;
}

.gantt-root.splitter-dragging * {
  /* 强制所有元素使用col-resize光标 */
  cursor: col-resize !important;
}
</style>
